package com.elizhang.redis.read;

import org.apache.log4j.Logger;
import org.springframework.data.redis.connection.RedisServer;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * <pre>
 * 
 * 	支持单个 master 及多个 slave 的主从模式。
 * 
 * 此类在初始化的时候会自动选择master下的某个slave进行连接，默认 5000 秒后会自动重新获取所有 slave ，然后选择某个 slave 进行拦截。
 * 
 * </pre>
 * @author ELI.ZHANG
 *
 * @param <V>
 * @param <K>
 */
public class ReadRedisTemplate<V, K>  extends RedisTemplate<K, V>{

	Logger logger = Logger.getLogger(getClass());

	private Timer timer;
	
	private JedisConnectionFactory jedisconnectionfactory;

	public void setJedisconnectionfactory(JedisConnectionFactory jedisconnectionfactory) {
		this.jedisconnectionfactory = jedisconnectionfactory;
	}

	/**
	 * 定时任务的时间间隔，定时重新获取最新的 slave
	 */
	private int period = 1*60*1000;
	
	public void setPeriod(int period) {
		this.period = period;
	}

	private void init(){

		if (timer != null) return;

		timer = new Timer();
		timer.schedule(new TimerTask() {

			@Override
			public void run() {
				initFactory();
			}
		}, period, period);

	}

	@PostConstruct
	private void initFactory(){

		Assert.notNull(jedisconnectionfactory, "JedisConectionfactory 不可为空!");

		Collection<RedisServer> masters = jedisconnectionfactory.getSentinelConnection().masters();

		for (RedisServer redisServer : masters) {

			// 获取所有的 slave
			Collection<RedisServer> slaves = jedisconnectionfactory.getSentinelConnection().slaves(redisServer);

			log("slaves - " + slaves.size());

			int slaveIndex = 0;

			if (slaves.size() > 1) {
				Random random = new Random();
				slaveIndex = random.nextInt(slaves.size());
			}

			RedisServer slave = (RedisServer) slaves.toArray()[slaveIndex];
			log("connected to host - " + slave.getHost() + " port - " + slave.getPort());
			setConnectionFactory(getConnectionfactory(slave.getHost(),slave.getPort()));
			afterPropertiesSet();

			break;
		}

		init();
	}

	private JedisConnectionFactory getConnectionfactory(String hostname, int port){
		
		JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
		connectionFactory.setHostName(hostname);
		connectionFactory.setPort(port);
		connectionFactory.afterPropertiesSet();
		
		return connectionFactory;
	}

	private void log(String message){
		logger.info(message);
	}
}

